//装饰器就是一个函数，只能在类中使用，（类本身、类成员使用）
//装饰器的分类：类的装饰器、方法装饰器、属性装饰器、参数装饰器
const classDecorator=<T extends new (...args:any[])=>any>(target:T)=>{
    (target as any).type="动物";
    (target as any).getType=()=>{
        return (this as any)?.type
    }
    Object.assign(target.prototype,{
        eat:()=>{},
        drink:()=>{}
    })

}
//1、类的装饰器，给类添加属性和方法、类的原型上的属性添加（一般不会通过装饰器，去给类添加属性和方法，应为扩展后，原来没有的方法无法反访问到namespace、interface来进行扩展）
interface Animal{
    drink():void
    eat():void
}
@classDecorator 
class Animal{

}
console.log((Animal as any).type);
const animal=new Animal()
console.log(1000,animal);
animal.drink()//会提示类型“Animal”上不存在属性“drink”。，添加上面interface Animal申明就可以使用

//1、类的装饰器：重写类
function OverrideAnimal(target:any){
    return class extends target{
        eat(){
            super.eat()
            console.log('new eat');
            
        }
    }
}
@OverrideAnimal
class Animal11{
    eat(){
        console.log('我在动物园');

    }
}

const animal12=new Animal11()
animal12.eat()
console.log(11000,animal12);

//2、方法装饰器
function Enum(isEnum:boolean):MethodDecorator{
    return function(target,properKey,desriptor){
        //给方法添加是否可枚举
        desriptor.enumerable=isEnum;
        const original=desriptor.value as any;
        //重写方法
        original.value=function(){
            return  original(...arguments)
        } 
    }
}
class Animal2{
@Enum(true)
    eat(){
        console.log('我在动物园2');

    }
}
const animal2=new Animal2()
console.log(2000,animal2);

//3、属性装饰器
function ToUpper(isUpper:boolean):PropertyDecorator{
    return function(target,propertyKey){
        let val=''
        // "module": "ESNext", 不同的module会有不同的处理方式，
        //相当于是拦截器，把小写转化为大写
        Object.defineProperty(target,propertyKey,{
            get(){
                return isUpper ? val.toLocaleUpperCase() : val
            },
            set(newVal){
                val=newVal
            }
        })

    }
}
class Animal3{
    @ToUpper(true)
    public name='animal3'
        eat(){
            console.log('我在动物园2');
    
        }
    }
const animal3=new Animal3()
console.log(3000,animal3);

//4、参数装饰器
//构造函数装饰器
//实例方法参数装饰器

export {}